#include "CUserActionEventReceiver.h"
#include "SUserAction.h"
//#include "pspdebug.h"
//#define printf pspDebugScreenPrintf
namespace game
{
	CUserActionEventReceiver::CUserActionEventReceiver(IDeviceManager* deviceManager) :		MouseMonitorThread(0),
																							MouseConfig(0),
																							DeviceManager(0),
																							IsRunning(false)
	{
		this->DeviceManager = deviceManager;
		this->DeviceManager->grab();

		this->MouseConfig = new SMouseConfig(deviceManager);

		KeyStates.insert(irr::KEY_UP, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_DOWN, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_LEFT, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_RIGHT, KEY_STATE_UP);

		KeyStates.insert(irr::KEY_START, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_SELECT, KEY_STATE_UP);

		KeyStates.insert(irr::KEY_TRIANGLE, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_CROSS, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_SQUARE, KEY_STATE_UP);
		KeyStates.insert(irr::KEY_CIRCLE, KEY_STATE_UP);


		irrThread::delegateThreadCallback* callback = new irrThread::delegateThreadCallback;

		*callback += NewDelegate(this, &CUserActionEventReceiver::monitorMouse);

		if(!callback->IsNull())
		{
			MouseMonitorThread = new irrThread(ETP_ABOVE_LOW, callback, "MouseMonitorThread", (void*)"");
		}

		MouseMonitorThread->start();
	}

	CUserActionEventReceiver::~CUserActionEventReceiver()
	{  
		if(MouseMonitorThread)
			delete MouseMonitorThread;

		if(DeviceManager)
			DeviceManager->drop();

	}

	void CUserActionEventReceiver::monitorMouse(void*)
	{
		while(true)
		{
			if(this->MouseConfig->getIsMoved())
			{
				monitorMouseInternal();
			}
			else
			{
				irrThread::sleep(100);
			}
		}

	}

	bool CUserActionEventReceiver::monitorMouseInternal()
	{
		bool result = false;

		u32 downTime = irr::os::Timer::getRealTime() - this->MouseConfig->getLastTimeMoved();

		if(downTime >300)
		{
			this->MouseConfig->setIsMoved(false);
			if(!this->UAction.IsNull())
			{
				SUserAction mouseAction;
				mouseAction.KeyCode = irr::KEY_MOUSE;
				mouseAction.KeyState = KEY_STATE_MOUSE_STOPPED;

				result = this->UAction(mouseAction);
			}
		}

		return result;
	}




	void CUserActionEventReceiver::startEventProcess()
	{
		this->IsRunning = true;

		resetKeyStates();
	}

	void CUserActionEventReceiver::stopEventProcess()
	{      
		this->IsRunning = false;

		resetKeyStates();
	}

	void  CUserActionEventReceiver::resetKeyStates()
	{
		irr::core::map<irr::EKEY_CODE, game::EKEY_STATE>::Iterator it = this->KeyStates.getIterator();

		it.reset(false);

		for(s32 i = this->KeyStates.size() - 1; i>=0; i--)
		{
			if(it.getNode()->getValue() == game::KEY_STATE_RELEASED)
			{
				it.getNode()->setValue(game::KEY_STATE_UP);
			}
			else if(it.getNode()->getValue() == game::KEY_STATE_PRESSED)
			{
				it.getNode()->setValue(game::KEY_STATE_DOWN);
			}
			it--;
		}
	}

	bool CUserActionEventReceiver::OnEvent(irr::SEvent event)
	{
		bool result = false;

		if(!IsRunning)
		{
			return result;
		}

		switch(event.EventType)
		{
		case irr::EET_KEY_INPUT_EVENT:
			{
				if(this->KeyStates.find(event.KeyInput.Key))
				{
					SUserAction keyInputAction;

					keyInputAction.KeyCode = event.KeyInput.Key;

					// if key is Pressed Down
					if (event.KeyInput.PressedDown == true)
					{
						if (this->KeyStates[event.KeyInput.Key] == KEY_STATE_PRESSED || this->KeyStates[event.KeyInput.Key] == KEY_STATE_DOWN)
						{
							// if key was down before
							this->KeyStates[event.KeyInput.Key] = KEY_STATE_DOWN; // Set to Down

							keyInputAction.KeyState = KEY_STATE_DOWN;
						}
						else // If key was not down before
						{
							this->KeyStates[event.KeyInput.Key] = KEY_STATE_PRESSED; // Set to Pressed

							keyInputAction.KeyState = KEY_STATE_PRESSED;
						}
					}
					else
					{
						// if the key is down
						if (this->KeyStates[event.KeyInput.Key] != KEY_STATE_UP)
						{
							this->KeyStates[event.KeyInput.Key] = KEY_STATE_RELEASED; // Set to Released
							keyInputAction.KeyState = KEY_STATE_RELEASED;
						}
					}

					if (!UAction.IsNull())
					{
						result = UAction(keyInputAction);
					}
				}

				break;
			}
		case irr::EET_MOUSE_INPUT_EVENT:
			{
				if(event.MouseInput.Event == irr::EMIE_MOUSE_MOVED)
				{
					SUserAction mouseAction;

					mouseAction.KeyCode = irr::KEY_MOUSE;
					mouseAction.KeyState= KEY_STATE_MOUSE_MOVE;

					mouseAction.MouseMovingInfo.X = this->MouseConfig->CurrentX - event.MouseInput.X;
					mouseAction.MouseMovingInfo.Y = this->MouseConfig->CurrentY - event.MouseInput.Y;

					this->MouseConfig->CurrentX = event.MouseInput.X;
					this->MouseConfig->CurrentY = event.MouseInput.Y;


					if(	event.MouseInput.X > this->MouseConfig->getMaxX() ||
						event.MouseInput.X < this->MouseConfig->getMinX() ||
						event.MouseInput.Y > this->MouseConfig->getMaxY() ||
						event.MouseInput.Y < this->MouseConfig->getMinY())
					{
						this->DeviceManager->getVideoDevice()->getCursorControl()->setPosition(this->MouseConfig->DefaultX, this->MouseConfig->DefaultY);
						this->MouseConfig->setIsMoved(true);

						if (!this->UAction.IsNull())
						{
							result = UAction(mouseAction);
						}


					}
					else if(mouseAction.MouseMovingInfo.X == 0 && mouseAction.MouseMovingInfo.Y == 0 && this->MouseConfig->getIsMoved())
					{
						printf("\nHandle this event, if you want");
						//result = this->monitorMouseInternal();

						result = true;	
					}
					else if(mouseAction.MouseMovingInfo.X == 0 && mouseAction.MouseMovingInfo.Y == 0 && !this->MouseConfig->getIsMoved())
					{
						result = true;
					}
					else if(mouseAction.MouseMovingInfo.X !=0 || mouseAction.MouseMovingInfo.Y !=0)
					{
						this->MouseConfig->setIsMoved(true);

						if(	mouseAction.MouseMovingInfo.X >= this->MouseConfig->getMaxOffsetX() ||
							mouseAction.MouseMovingInfo.Y >= this->MouseConfig->getMaxOffsetY() ||
							mouseAction.MouseMovingInfo.X <= this->MouseConfig->getMinOffsetX() ||
							mouseAction.MouseMovingInfo.Y <= this->MouseConfig->getMinOffsetY())
						{
							//dummy
							result = true;
						}
						else if(!this->UAction.IsNull())
						{
							result = this->UAction(mouseAction);
						}
					}
				}

				break;
			}
		default: 
			{
			break;
			}
		}

		return result;
	}


	IUserActionEventReceiver* createUserActionEventReceiver(IDeviceManager* deviceManager)
	{
		IUserActionEventReceiver* result = new CUserActionEventReceiver(deviceManager);

		return result;
	}

}